﻿using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Collections.Specialized;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.ComponentModel;
using System.Windows;
using System.Windows.Data;

namespace ChatBox.Utilities
{
  /// <summary>
  /// Represents a dynamic data collection that raises notifications when items are
  /// added, removed, moved or replaced. In addition, this collection also has a View property
  /// that offers a bindable version of this collection. Note that this collection can only be
  /// edited on the UI thread.
  /// </summary>
  /// <typeparam name="T">The type of items in this collection.</typeparam>
  public class ViewableCollection<T> : ObservableCollection<T>
  {
    #region Constructors

    /// <summary>
    /// Initializes a new instance of the <see cref="T:ChatBox.ViewableCollection`1"/> class.
    /// </summary>
    public ViewableCollection()
      : base()
    {
    }

    /// <summary>
    /// Initializes a new instance of the <see cref="T:ChatBox.ViewableCollection`1"/> class that contains elements copied from the specified collection.
    /// </summary>
    /// <param name="collection">The collection from which the elements are copied.</param>
    /// <exception cref="T:System.ArgumentNullException">The <paramref name="collection"/> parameter cannot be null.</exception>
    public ViewableCollection( IEnumerable<T> collection )
      : base( collection )
    {
    }

    #endregion

    #region Public Properties

    /// <summary>
    /// Gets a bindable view of this observable collection (of T) that supports
    /// filtering, sorting and grouping.
    /// </summary>
    public ListCollectionView View
    {
      get
      {
        if ( _view == null )
        {
          _view = new ListCollectionView( this );
        }

        return _view;
      }
    }

    #endregion

    #region Public Methods

    /// <summary>
    /// Makes sure the added items are connected and the removed items disconnected.
    /// </summary>
    /// <param name="listener">Instance that will listen to the property changed events.</param>
    /// <param name="e">Event arguments received in the CollectionChanged event handler.</param>
    /// <param name="newItemAction">Action to call for each new items.</param>
    public void KeepConnected( IWeakEventListener listener, NotifyCollectionChangedEventArgs e, Action<T> newItemAction )
    {
      if ( e != null )
      {
        if ( e.OldItems != null )
        {
          foreach ( T oldItem in e.OldItems )
          {
            PropertyChangedEventManager.RemoveListener( ( INotifyPropertyChanged )oldItem, listener, String.Empty );
          }
        }

        if ( e.NewItems != null )
        {
          if ( newItemAction != null )
          {
            foreach ( T newItem in e.NewItems )
            {
              PropertyChangedEventManager.AddListener( ( INotifyPropertyChanged )newItem, listener, String.Empty );
              newItemAction( newItem );
            }
          }
          else
          {
            foreach ( T newItem in e.NewItems )
            {
              PropertyChangedEventManager.AddListener( ( INotifyPropertyChanged )newItem, listener, String.Empty );
            }
          }
        }
      }
    }

    #endregion

    #region Private Variables

    private ListCollectionView _view = null;

    #endregion
  }
}
